<!--
 * @Description:  公用弹窗
 * @Version: 2.0
 * @Autor: ChenWan
 * @Date: 2022-11-09 15:35:40
 * @LastEditors: xzh
 * @LastEditTime: 2023-08-08 17:34:27
-->

<template>
  <transition name="el-fade-in">
    <div
      v-if="dialogVisible"
      class="layer-container"
      :style="{ zIndex: floatZIndex }"
      @mousemove="handleMousemove($event)"
      @mouseup="handleMouseup($event)"
      @mouseleave="handleMouseup($event)"
    >
      <!-- <div class="layer-mask" @click="handleClose"></div> -->
      <div
        class="layer-win"
        :style="{
          width: width + 'px',
          height: height + 'px',
          left: left + 'px',
          top: top + 'px',
        }"
      >
        <slot name="left"></slot>
        <div class="layer-main-container">
          <div class="layer-header" @mousedown="moveHandleMousedown($event)">
            <p>{{ title }}</p>
            <div class="layer-fn-btns">
              <i @click.stop="handleFullScreen(1)" v-if="fullScreen">
                <el-icon>
                  <CopyDocument />
                </el-icon>
              </i>
              <i @click.stop="handleFullScreen(2)" v-if="!fullScreen">
                <el-icon>
                  <FullScreen />
                </el-icon>
              </i>
              <i @click.stop="handleClose">
                <el-icon>
                  <Close />
                </el-icon>
              </i>
            </div>
          </div>
          <div class="layer-content">
            <div class="layer-content-mask" v-if="acType > 0"></div>
            <!-- 防止在内部存在iframe，在拖动或者缩放时鼠标在iframe上时脱离原网页坐标而无法监听鼠标位置 -->
            <div
              :class="{
                'has-bottom-dialog': !!footerVisible || !!useSlots().footer,
                content: true,
              }"
            >
              <el-scrollbar>
                <slot />
              </el-scrollbar>
            </div>
            <div
              class="dialog-footer"
              v-if="!!footerVisible || !!useSlots().footer"
            >
              <template v-if="footerVisible">
                <el-button text @click.stop="handleClose">{{
                  $t("common.cancel")
                }}</el-button>
                <el-button v-if="showSave" type="success" @click="sure">
                  {{ sureText || $t("common.define") }}
                </el-button>
              </template>
              <slot name="footer"> </slot>
            </div>
          </div>
        </div>
        <div class="scale-btn" @mousedown="scaleHandleMousedown($event)"></div>
      </div>
    </div>
  </transition>
</template>

<script setup lang="ts">
import { ref, reactive, watch, onMounted, useSlots, onUnmounted } from "vue";
import { Close, FullScreen, CopyDocument } from "@element-plus/icons-vue";

const emit = defineEmits(["update:modelValue", "close", "sure"]);
const props = defineProps({
  sureText: String, //确定按钮自定义文案

  // 底部按钮是否显示
  footerVisible: {
    type: Boolean,
    requited: false,
    default: true,
  },
  //定义弹窗宽度
  layerWidth: {
    type: [Number, String],
    requited: false,
    default: 800,
  },
  //定义弹窗高度
  layerHeight: {
    type: [Number, String],
    requited: false,
    default: 500,
  },
  //定义弹窗距左边界距离
  layerLeft: {
    type: Number,
    requited: false,
    default: 0,
  },
  //定义弹窗距顶部距离
  layerTop: {
    type: Number,
    requited: false,
    default: 0,
  },
  //定义弹窗显标题
  title: {
    type: String,
    requited: false,
    default: "",
  },
  //缩放最小宽度 默认200px
  miniW: {
    type: Number,
    requited: false,
    default: 200,
  },
  //缩放最小高度 默认200px
  miniH: {
    type: Number,
    requited: false,
    default: 200,
  },
  // 是否显示保存按钮
  showSave: {
    type: Boolean,
    requited: false,
    default: true,
  },
  modelValue: {
    type: Boolean,
    requited: false,
    default: false,
  },
});

let dialogVisible = ref<boolean>(props.modelValue); //弹窗开关
let acType = ref<number>(-1); //定义操作弹窗动作类型 1为缩放 2为拖动

let visWidth = ref<number>(1000); //保存页面文档宽度
let visHeight = ref<number>(1000); //保存页面文档高度

let width = ref<number>(800); //弹窗实际操作高度
let height = ref<number>(500); //弹窗实际操作宽度
let left = ref<number>(0); //弹窗距文档左边实际操作距离
let top = ref<number>(0); //弹窗距顶部实际操作距离

let scale = reactive({
  stX: 0,
  stY: 0,
  currW: 0,
  currH: 0,
}); //定义缩放临时参数

let move = reactive({
  stX: 0,
  stY: 0,
  currL: 0,
  currT: 0,
}); //定义拖动临时参数

let fullScreen = ref<boolean>(false); //定义全屏弹窗状态
let fsWidth = ref<number>(0);
let fsHeight = ref<number>(0); //全屏显示时保存弹窗非全屏显示时的大小与状态
let fsLeft = ref<number>(0);
let fsTop = ref<number>(0);
let floatZIndex = ref<number>(2010);

//定义弹窗显示状态属性 默认false

//监听弹窗的显示状态 初始弹窗位置与大小
watch(
  () => props.modelValue,
  (newV: boolean, oldV: boolean) => {
    dialogVisible.value = newV;
    emit("update:modelValue", newV);
    if (newV) {
      let divs = <any>document.querySelectorAll(".el-overlay");
      let max: number = 0;
      for (let i = 0; i < divs.length; i++) {
        max = Math.max(max, divs[i]?.style.zIndex || 0);
      }
      if (max > 0) {
        //有右侧面板
        floatZIndex.value = max + 1;
      }

      let currentWidth = props.layerWidth,
        currentHeight = props.layerHeight;
      //宽高传入百分比处理
      if (
        typeof props.layerWidth == "string" &&
        props.layerWidth.includes("%")
      ) {
        const folatWidth = parseFloat(props.layerWidth.replace("%", "")) / 100;
        currentWidth =
          folatWidth *
          (document.documentElement.clientWidth || document.body.clientWidth);
      }
      if (
        typeof props.layerHeight == "string" &&
        props.layerHeight.includes("%")
      ) {
        const folatHeight =
          parseFloat(props.layerHeight.replace("%", "")) / 100;
        currentHeight =
          folatHeight *
          (document.documentElement.clientHeight || document.body.clientHeight);
      }

      //如未定义弹窗位置则默认居中
      if (!props.layerLeft) {
        const padLeft = (visWidth.value - Number(currentWidth)) / 2;
        left.value = padLeft < 0 ? 0 : padLeft;
      }
      if (!props.layerTop) {
        const padTop = (visHeight.value - Number(currentHeight)) / 2;
        top.value = padTop < 0 ? 0 : padTop;
      }
      width.value =
        left.value === 0 ? document.body.clientWidth : Number(currentWidth);
      height.value =
        top.value === 0 ? document.body.clientHeight : Number(currentHeight);
      fullScreen.value = false;
    } else {
      emit("close"); //关闭弹窗
    }
  }
);

onMounted(() => {
  getDocSize(); //初始获取文档宽高
  window.addEventListener("resize", handleResize);
});

onUnmounted(() => {
  window.removeEventListener("resize", handleResize);
});

let handleResize = () => {
  getDocSize(); //监听window 宽高发生变化时 重新获取宽高
  if (fullScreen.value) {
    //全屏状态下更新弹窗宽高
    width.value = visWidth.value;
    height.value = visHeight.value;
  }
};

const getDocSize = () => {
  visWidth.value =
    document.documentElement.clientWidth || document.body.clientWidth;
  visHeight.value =
    document.documentElement.clientHeight || document.body.clientHeight;
};

const scaleHandleMousedown = (e: any) => {
  //缩放弹窗 开始
  if (fullScreen.value) return; //全屏时禁止缩放
  acType.value = 1;
  scale.stX = e.clientX;
  scale.stY = e.clientY;
  scale.currW = Number(width.value);
  scale.currH = Number(height.value);
};

const moveHandleMousedown = (e: any) => {
  //拖动弹窗 开始
  if (fullScreen.value) return;
  acType.value = 2;
  move.stX = e.clientX;
  move.stY = e.clientY;
  move.currL = left.value;
  move.currT = top.value;
};

const handleMouseup = (e: any) => {
  //结束操作
  acType.value = -1;
  triggerResize();
};

const handleMousemove = (e: any) => {
  if (acType.value === 1) {
    //缩放
    let crW = 0,
      crH = 0;
    crW = scale.currW + (e.clientX - scale.stX);
    crH = scale.currH + (e.clientY - scale.stY);
    if (crW <= props.miniW) {
      width.value = props.miniW;
    } else {
      width.value = crW;
    }
    if (crH <= props.miniH) {
      height.value = props.miniH;
    } else {
      height.value = crH;
    }
  }
  if (acType.value === 2) {
    //移动
    let paddingLeft = move.currL + (e.clientX - move.stX);
    let paddingTop = move.currT + (e.clientY - move.stY);
    if (paddingLeft < 0) {
      //左边
      paddingLeft = 0;
    }

    if (paddingTop < 0) {
      //上边
      paddingTop = 0;
    }

    let maxRight = document.body.clientWidth - Number(width);
    if (paddingLeft > maxRight) {
      //超过右侧不可拖拽
      paddingLeft = maxRight;
    }

    let maxBottom = document.body.clientHeight - Number(height);
    if (paddingTop > maxBottom) {
      //超过底部不可拖拽
      paddingTop = maxBottom;
    }
    left.value = paddingLeft;
    top.value = paddingTop;
  }
};

const handleClose = () => {
  dialogVisible.value = false;
  emit("update:modelValue", false);
};
const handleFullScreen = (type: number) => {
  //全屏
  if (type == 1) {
    if (!fullScreen.value) return;
    fullScreen.value = false;

    width.value = fsWidth.value;
    height.value = fsHeight.value;
    left.value = fsLeft.value;
    top.value = fsTop.value;
  } else {
    if (fullScreen.value) return;
    fullScreen.value = true;

    fsWidth.value = Number(width.value);
    fsHeight.value = Number(height.value);
    fsLeft.value = left.value;
    fsTop.value = top.value;

    width.value = visWidth.value;
    height.value = visHeight.value;
    left.value = 0;
    top.value = 0;
  }
  setTimeout(triggerResize, 500);
};

// 确定
const sure = () => {
  emit("sure");
};

// 手动触发resize（截图那里改变弹窗大小有问题）
const triggerResize = () => {
  const myEvent = new Event("resize");
  window.dispatchEvent(myEvent);
};

defineExpose({});
</script>
<style lang="scss" scoped></style>
